<template>
  <div id="qaOnline" style="position: relative; background-color: Gainsboro">
    <el-card>
      <el-row>
        <el-col :span="23" :xs="24">
          <el-form :inline="true" label-width="90px">
            <el-form-item :label="'验收状态：'" :label-position="'left'" style="margin-top: -5px; margin-bottom: -30px">
              {{ currentStatus }}
            </el-form-item>
            <el-form-item
              v-if="fileList[currentIndex] && fileList[currentIndex].updateBy && checkrole(['admin', 'checker'])"
              :label="'标注员：'"
              :label-position="'left'"
              style="margin-top: -5px; margin-bottom: -30px"
            >
              {{ fileList[currentIndex].updateBy }}
            </el-form-item>
            <el-form-item
              v-if="fileList[currentIndex] && fileList[currentIndex].updateTime && checkrole(['admin', 'checker'])"
              :label="'更新时间：'"
              :label-position="'left'"
              style="margin-top: -5px; margin-bottom: -30px"
            >
              {{ fileList[currentIndex].updateTime }}
            </el-form-item>
            <el-form-item style="margin-top: -5px; margin-bottom: -30px">
              <el-input id="remarkInput" type="text" placeholder="批注" size="mini" v-model="remark" />
            </el-form-item>
            <el-form-item v-if="checkrole(['admin', 'qa'])" style="margin-top: -5px; margin-bottom: -30px">
              <el-tooltip effect="dark" content="通过" placement="bottom">
                <el-button type="success" size="mini" @click="handleComments('通过')" icon="el-icon-check" circle />
              </el-tooltip>
            </el-form-item>
            <el-form-item v-if="checkrole(['admin', 'qa'])" style="margin-top: -5px; margin-bottom: -30px">
              <el-tooltip effect="dark" content="驳回" placement="bottom">
                <el-button type="danger" size="mini" @click="handleComments('驳回')" icon="el-icon-close" circle />
              </el-tooltip>
            </el-form-item>
            <el-form-item v-if="checkrole(['admin', 'qa'])" style="margin-top: -5px; margin-bottom: -30px">
              <el-tooltip effect="dark" content="挂起" placement="bottom">
                <el-button type="warning" size="mini" @click="handleComments('挂起')" icon="el-icon-sort-down" circle />
              </el-tooltip>
            </el-form-item>
            <el-form-item style="margin-top: -5px; margin-bottom: -30px">
              <el-tooltip effect="dark" content="全屏" placement="bottom">
                <el-button
                  v-if="!isFullscreen"
                  type="primary"
                  size="mini"
                  @click="threejsFullScreen()"
                  icon="el-icon-full-screen"
                  circle
                />
              </el-tooltip>
              <el-tooltip effect="dark" content="退出全屏" placement="bottom">
                <el-button
                  v-if="isFullscreen"
                  type="primary"
                  size="mini"
                  @click="threejsFullScreen()"
                  icon="el-icon-aim"
                  circle
                />
              </el-tooltip>
            </el-form-item>
            <el-form-item style="margin-top: -5px; margin-bottom: -30px">
              <el-input id="trackID" type="text" placeholder="TrackID" size="mini" v-model="selectedObject.a1" />
            </el-form-item>
            <el-form-item style="margin-top: -5px; margin-bottom: -30px">
              <el-tooltip effect="dark" content="查找TrackId" placement="bottom">
                <el-button type="primary" size="mini" @click="highlight_objects('')" icon="el-icon-search" circle />
              </el-tooltip>
            </el-form-item>
            <el-form-item style="margin-top: -5px; margin-bottom: -30px">
              <el-tooltip effect="dark" content="批注列表" placement="bottom">
                <el-button
                  type="primary"
                  size="mini"
                  @click="() => this.$refs.remarkList.show(null)"
                  icon="el-icon-notebook-2"
                  circle
                />
              </el-tooltip>
            </el-form-item>
          </el-form>
        </el-col>
        <el-col :span="1" :xs="24">
          <el-form :inline="true" label-width="68px">
            <el-form-item style="margin-top: -5px; margin-bottom: -30px">
              <el-tooltip effect="dark" content="返回文件列表" placement="bottom">
                <el-button type="primary" icon="el-icon-d-arrow-left" size="mini" @click="returnFileList()" circle />
              </el-tooltip>
            </el-form-item>
          </el-form>
        </el-col>
      </el-row>
    </el-card>
    <div id="container" class="point-cloud-container" style="height: 83vh" v-loading="loading && seconds > 1">
      <canvas id="canvas3d" />
    </div>
    <div id="bottomDiv" class="bottom-div">
      <el-row :gutter="20">
        <el-col :span="9" :xs="24">
          <el-form :inline="true">
            <el-form-item style="display: table-cell; width: 100%; text-align: left">
              <div class="filename">
                <span>{{ taskPath }}</span>
              </div>
            </el-form-item>
          </el-form>
        </el-col>
        <el-col :span="6" :xs="24">
          <el-form align="center">
            <el-form-item style="">
              <el-button
                type="primary"
                size="mini"
                :disabled="loading || currentIndex <= 0"
                @click="changePage(-1)"
                icon="el-icon-back"
                circle
              />
              <span
                >&nbsp;&nbsp;&nbsp;&nbsp;当前：({{ currentIndex + 1 }} /
                {{ fileList.length }})&nbsp;&nbsp;&nbsp;&nbsp;</span
              >
              <el-button
                type="primary"
                size="mini"
                :disabled="loading || currentIndex >= fileList.length - 1"
                @click="changePage(1)"
                icon="el-icon-right"
                circle
              />
              &nbsp;
              <el-select
                :value="currentIndex + 1"
                @change="
                  (value) => {
                    changePage(value - 1 - currentIndex)
                  }
                "
                style="width: 80px"
              >
                <el-option v-for="(item, index) in fileList" :key="item.fileId" :label="index + 1" :value="index + 1">
                </el-option>
              </el-select>
            </el-form-item>
          </el-form>
        </el-col>
        <el-col :span="9" :xs="24">
          <el-form :inline="true">
            <el-form-item style="display: table-cell; width: 100%; text-align: right">
              <div class="filename">
                <span v-if="fileList[currentIndex]">{{ fileList[currentIndex].fileId }}&nbsp;</span>
              </div>
            </el-form-item>
            <el-form-item style="display: table-cell">
              <el-popover
                placement="top-end"
                width="360"
                :visible-arrow="false"
                trigger="hover"
                @show="showColorDialogVar = true"
                @hide="showColorDialogVar = false"
              >
                <div>
                  <div id="colorPanel" class="icon-list">
                    <div>
                      <p>属性色块：</p>
                    </div>
                    <div class="color-name" v-for="dict in colorNames" :key="dict.dictValue">
                      <svg :style="'height: 18px;width: 18px;'">
                        <rect width="18px" height="18px" :style="'fill:' + dict.dictLabel" />
                      </svg>
                      <span>{{ dict.dictValue }}</span>
                    </div>
                  </div>
                </div>
                <el-button slot="reference" type="text" :disabled="isFullscreen" class="color-name-btn">
                  属性色块
                  <i
                    style="transform: rotate(90deg)"
                    :class="showColorDialogVar ? 'el-icon-d-arrow-right' : 'el-icon-d-arrow-left'"
                  ></i>
                </el-button>
              </el-popover>
            </el-form-item>
          </el-form>
        </el-col>
      </el-row>
    </div>
    <el-dialog append-to-body :title="'目标信息'" :visible.sync="detailsDialogOpen" width="600px">
      <el-form :model="selectedObject" label-position="right" label-width="80px">
        <el-form-item v-for="attribute in selectedObject.attributes" :key="attribute.key" :label="attribute.key + ': '">
          <el-input v-model="attribute.value" maxlength="50" readonly />
        </el-form-item>
        <el-form-item label="错误类型" prop="errorType">
          <el-select v-model="selectedObject.errorType" placeholder="请选择错误类型" clearable size="small">
            <el-option
              v-for="dict in errorTypeOptions"
              :key="dict.dictValue"
              :label="dict.dictLabel"
              :value="dict.dictValue"
            />
          </el-select>
        </el-form-item>
        <el-form-item :label="'目标批注: '">
          <el-input
            id="detailRemarkInput"
            maxlength="80"
            placeholder="请在此输入针对改目标的批注"
            v-model="selectedObject.remark"
          />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="handleElementComments(selectedObject.a1, selectedObject.remark)"
          >提 交</el-button
        >
        <el-button @click="detailsDialogOpen = false">取 消</el-button>
      </div>
    </el-dialog>
    <div id="focus_toolTip" class="special_focus_toolTip" v-html="toolTopbody" />
    <RemarkList
      ref="remarkList"
      :task-id="queryParams.taskId"
      :set-position="setPosition"
      :delete-remark="deleteRemark"
      :update-remark="updateRemark"
    />
  </div>
</template>

<script>
import $ from 'jquery'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { PCDLoader } from './PCDLoader.js'
import { pointsCloudDetails, imageFile, pcdBlob } from '@/api/mark/onlineCheckV1'
import { listResult, updateResult } from '@/api/mark/qaresult'
import { getQaTask } from '@/api/mark/qaTaskV1'
import screenfull from 'screenfull'
import { Vector2 } from 'three'
import { checkRole } from '@/utils/permission'
import { colorRender, hsvToRgb } from './PCDColorRender.js'
import SliderContainer from './components/SliderContainer'
import PlaneView from './components/PlaneView'
import RemarkList from './components/RemarkList'
import { listRemarkBall, getRemarkBall, delRemarkBall, addRemarkBall, updateRemarkBall } from '@/api/mark/remarkBall'

export default {
  name: 'FuseEditor',
  components: {
    SliderContainer,
    PlaneView,
    RemarkList,
  },
  data() {
    return {
      taskPath: '',
      seconds: 0,
      interval: undefined,
      scaleFactor: undefined,
      showAttributesText: true,
      animationFrameId: undefined,
      mouseDown: false,
      renderEnabled: false,
      pointTextFontSize: 48,
      detailsDialogOpen: false,
      showColorDialogVar: false,
      isFullscreen: false,
      queryParams: {
        taskId: undefined,
      },
      selectedObject: {
        a1: '',
        remark: '',
        attributes: [],
        type: '',
        imageIndex: '',
        errorType: '',
        mPoint: {
          x: -1,
          y: -1,
          z: -1,
        },
        elementInstance: null,
        position: null,
      },
      errorTypeOptions: [],
      currentSelection: {},
      colorNames: {},
      attributeNames: {},
      // imgIndex: -1,
      imgCount: 0,
      tipContent: '',
      colorBody: '',
      toolTopbody: '',
      ctx: null,
      canvasIndex: -1,
      remarkMap: new Map(), // 批注图标
      viewWidth: 0,
      viewHeight: 0,
      imageWidth: 0,
      imageHeight: 0,
      viewZoom: null,
      factor: 1.25,
      maxZoom: 80,
      disabledComposition: false,

      loading: true,
      startLoading: false,
      container: null,
      camera: null,
      scene: null,
      highlight_points: null,
      controls: null,
      renderer: null,
      points: null,
      keyPoints: [],
      cubeList: new Array(),
      cubeInstances: new Array(),
      lineList: new Array(),
      cubeMap: new Map(),
      remarkLabelList: new Array(),
      txtGeo: null,
      txtMater: null,
      raycaster: null,
      mouse: null,
      pointsCloudData: null,
      annotation: null,
      currentStatus: '',
      currentIndex: -1,
      fileList: {},
      remark: null,
      elementsRemark: {},
      elements_3D: [],
      INTERSECTED: null,
      annotation2d: new Array(),
      renderType: '',
      highLightCubePoints: 'false',
      cameraPosition: null,
      planeViewDrawer: false,
      selectedObjectA1: null,
      selectPointObject: null,
    }
  },
  methods: {
    checkrole(role) {
      return checkRole(role)
    },
    setPosition(a1, mQaResultId, remark, type, imageIndex, errorType, point, position) {
      if (!a1) return
      this.selectedObjectA1 = a1
      if (this.fileList && mQaResultId && this.fileList[this.currentIndex].mQaResultId != mQaResultId) {
        for (let i = 0; i < this.fileList.length; i++) {
          if (this.fileList[i].mQaResultId == mQaResultId) {
            this.changePage(i - this.currentIndex)
          }
        }
      }
      this.selectedObject.a1 = a1
      this.selectedObject.remark = remark
      this.selectedObject.type = type
      this.selectedObject.imageIndex = imageIndex
      this.selectedObject.errorType = errorType
      this.highlight_objects('')
    },
    deleteRemark(a1, type, elementsRemarkKey) {
      // 这里处理重新打开批注弹框时的remark input值
      if (this.selectedObject.a1 == a1 && type && this.selectedObject.type == type) {
        this.selectedObject.remark = ''
      }
      // 删除 this.elementsRemark 对应的记录
      let item = this.remarkMap.get(elementsRemarkKey)
      if (item && type == '2d') {
        item.remove()
        item.markRemarkId && item.textObject.remove()
      }
      this.elementsRemark[elementsRemarkKey] = null
      this.elementsRemark['ball-' + elementsRemarkKey] = null
      this.remarkMap.delete(elementsRemarkKey)
      this.reRender()
    },
    updateRemark(a1, type, elementsRemarkKey, remark) {
      // 这里处理重新打开批注弹框时的remark input值
      if (this.selectedObject.a1 == a1 && type && this.selectedObject.type == type) {
        this.selectedObject.remark = remark
      }
      this.elementsRemark[elementsRemarkKey] = remark
      if (this.elementsRemark['ball-' + elementsRemarkKey])
        this.elementsRemark['ball-' + elementsRemarkKey].remark = remark
      this.reRender()
    },
    reRender() {
      for (let m = 0; m < this.mainLayer.length; m++) {
        if (!this.mainLayer[m]) continue
        let items = this.mainLayer[m].getItems()
        for (let i = 0; i < items.length; i++) {
          if (items[i].tag) {
            let itemA1 = items[i].tag.split(';')[1]
            if (this.elementsRemark[itemA1 + '-2d-' + m]) {
              items[i].missObject.opacity = 1
              items[i].missObject.textBackground.opacity = 1
            } else {
              items[i].missObject.opacity = 0
              items[i].missObject.textBackground.opacity = 0
            }
          }
        }
      }
      for (let i = 0; i < this.remarkLabelList.length; i++) {
        if (this.elementsRemark[this.remarkLabelList[i].missId]) {
          this.scene.add(this.remarkLabelList[i])
        } else {
          this.scene.remove(this.remarkLabelList[i])
        }
      }
      this.renderer.render(this.scene, this.camera)
    },
    calcCameraOffsetPosition(selectCubeCenterPoint, distance) {
      // x0,y0,z0为摄像机重新定位前的位置
      let x0 = this.camera.position.x
      let y0 = this.camera.position.y
      let z0 = this.camera.position.z
      // 根据新旧目标位移差计算摄像机新坐标
      x0 = selectCubeCenterPoint.x - this.controls.target.x + x0
      y0 = selectCubeCenterPoint.y - this.controls.target.y + y0
      z0 = selectCubeCenterPoint.z - this.controls.target.z + z0
      let x = selectCubeCenterPoint.x
      let y = selectCubeCenterPoint.y
      let z = selectCubeCenterPoint.z
      // 计算拉近摄像机后摄像机坐标
      let x1 = (distance * (x0 - x)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + x
      let y1 = (distance * (y0 - y)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + y
      let z1 = (distance * (z0 - z)) / Math.sqrt((x0 - x) * (x0 - x) + (y0 - y) * (y0 - y) + (z0 - z) * (z0 - z)) + z
      return { x1: x1, y1: y1, z1: z1 }
    },
    calcCubeCenterPoint(eight_points) {
      // 找出矩形最长边长度值，乘以distance系数，让矩形最大边可以完整显示在摄像机内
      let maxL = 0,
        maxW = 0,
        maxH = 0
      for (let i = 3; i < 24; i += 3) {
        maxL = Math.max(Math.abs(eight_points[i] - eight_points[i - 3]), maxL)
        maxW = Math.max(Math.abs(eight_points[i + 1] - eight_points[i + 1 - 3]), maxW)
        maxH = Math.max(Math.abs(eight_points[i + 2] - eight_points[i + 2 - 3]), maxH)
      }
      // 查找矩形的中心位置，计算长宽高的中点，用长宽高的一半加上x,y,z轴最小值
      let x = Math.min(eight_points[0], eight_points[6]) + maxL / 2
      let y = Math.min(eight_points[1], eight_points[7]) + maxW / 2
      let z = Math.min(eight_points[2], eight_points[23]) + maxH / 2
      return {
        x: x,
        y: y,
        z: z,
        maxL: maxL,
        maxW: maxW,
        maxH: maxH,
      }
    },
    HideTip() {
      $('#focus_toolTip').css('display', 'none')
    },
    ShowTip(message, x, y) {
      if (this.detailsDialogOpen) return
      let focusTooltip = $('#focus_toolTip')
      focusTooltip.css('left', x + 'px')
      focusTooltip.css('top', y + 'px')
      focusTooltip.css('z-index', 9999)
      let attrs = message.split(';')
      let _values
      try {
        let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelName'))
        _values = jsonObject.values[attrs[0].split(':')[0]]
      } catch (e) {}
      if (_values == null || _values == undefined || _values == '') _values = attrs[0].split(':')[0]
      message = '类型：' + _values
      message += '<br>'
      let _d = attrs[0].split(':')[1]
      for (let i = 1; i <= 9; i++) {
        if (attrs[i] && attrs[i] != null && attrs[i] != '' && attrs[i] != 'null') {
          try {
            let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_' + _d + 'd'))
            let _values = jsonObject.values[attrs[i]]
            if (_values == null || _values == undefined || _values == '') _values = attrs[i]
            message += jsonObject.typeDesc + ': ' + _values + '&nbsp<br>'
          } catch {}
        }
      }
      let headerHtml =
        "<div style='font-size:12px; color: #fec443; font-weight: bold; font-family: MicrosoftYaHei;'>" +
        message +
        '</div>'
      let effectHtml = "<div style='font-size:12px;margin-top:3px;' >" + '</div>'
      this.toolTopbody = headerHtml + effectHtml
      focusTooltip.css('display', 'block')
    },
    ShowAttributesText(show) {
      let opacity = show ? 1 : 0
      for (let m = 0; m < this.mainLayer.length; m++) {
        if (!this.mainLayer[m]) continue
        let items = this.mainLayer[m].getItems()
        for (let i = 0; i < items.length; i++) {
          if (items[i].textObject) {
            items[i].textObject.opacity = opacity
          }
        }
      }
    },
    init() {
      this.container = document.getElementById('container')
      let canvas3d = document.getElementById('canvas3d')
      this.raycaster = new THREE.Raycaster()
      this.mouse = new THREE.Vector2()
      this.scene = new THREE.Scene()
      this.camera = new THREE.PerspectiveCamera(
        10,
        this.container.offsetWidth / this.container.offsetHeight,
        0.1,
        10000
      )
      try {
        let tmpPosition = JSON.parse(this.cameraPosition)
        this.camera.position.x = tmpPosition.x
        this.camera.position.y = tmpPosition.y
        this.camera.position.z = tmpPosition.z
      } catch {
        this.camera.position.x = 0
        this.camera.position.y = 400
        this.camera.position.z = 300
      }
      this.camera.up.set(0, 0, 1)
      this.camera.lookAt(new THREE.Vector3(0, 0, 0))
      this.scene.add(this.camera)

      let ambientLight = new THREE.AmbientLight(0xffffff)
      this.scene.add(ambientLight)

      this.scene = new THREE.Scene()
      this.scene.background = new THREE.Color(0x111111)

      // 添加坐标轴
      let axesHelper = new THREE.AxesHelper(5)
      this.scene.add(axesHelper)
      if (this.renderer != null) {
        this.renderer.forceContextLoss()
        this.renderer = null
      }

      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        canvas: canvas3d,
        powerPreference: 'high-performance',
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
      this.container.appendChild(this.renderer.domElement)

      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      this.controls.zoomSpeed = 3
      this.controls.panSpeed = 2
      this.controls.rotateSpeed = 1
      this.controls.maxPolarAngle = Math.PI * 0.5
      this.renderer.domElement.addEventListener('mousemove', this.onMouseMove, false)
      this.renderer.domElement.addEventListener('mousedown', this.onMouseDown, false)
      this.renderer.domElement.addEventListener('mouseup', this.onMouseUp, false)
      this.renderer.domElement.addEventListener('wheel', this.onMouseWheel, false)
    },
    addPoints() {
      if (this.pointsCloudData) {
        if (this.points) {
          try {
            this.scene.remove(this.points)
            this.points.geometry.dispose()
            this.points.material.dispose()
          } catch (e) {
            console.log(e)
          }
        }
        this.points = this.pointsCloudData
        this.scene.add(this.points)
      }
      if (this.keyPoints.length > 0) {
        for (let i = 0; i < this.keyPoints.length; i++) {
          this.keyPoints[i].geometry.dispose()
          this.keyPoints[i].material.dispose()
          this.scene.remove(this.keyPoints[i])
        }
      }
      if (this.highlight_points) {
        this.scene.remove(this.highlight_points)
      }
      if (this.selectPointObject) {
        this.scene.remove(this.selectPointObject)
      }
    },
    // https://www.cnblogs.com/pozhu15/p/11951320.html
    gerColorOfWeight(minNum, maxNum, colorStart, colorend, number) {
      let colorR = ((colorend['red'] - colorStart['red']) * (number - minNum)) / (maxNum - minNum) + colorStart['red']
      let colorG =
        ((colorend['green'] - colorStart['green']) * (number - minNum)) / (maxNum - minNum) + colorStart['green']
      let colorB =
        ((colorend['blue'] - colorStart['blue']) * (number - minNum)) / (maxNum - minNum) + colorStart['blue']
      let color = [parseInt(colorR), parseInt(colorG), parseInt(colorB)]
      return color
    },
    addSplitPoints() {
      let geometry_temp = new THREE.BufferGeometry()
      let positions_temp = []
      let colors_temp = []
      let stringPairs = this.annotation.object.split('\r\n')
      // for(let i = 0; i<this.points.geometry.attributes.position.count; i++) {
      for (let i = 0; i < stringPairs.length; i++) {
        // if(this.points.geometry.attributes.customColumn.array[2*i +1]
        //   && this.points.geometry.attributes.customColumn.array[2*i +1] != -1) {
        let tmpArray = stringPairs[i].split(' ')
        let pointIndex = parseInt(tmpArray[0])
        let pointType = parseInt(tmpArray[1])
        if (isNaN(pointType)) {
          continue
        }
        // this.points.geometry.attributes.color.array[3 * pointIndex] = 1.0;
        // this.points.geometry.attributes.color.array[3 * pointIndex + 1] = 0.0;
        // this.points.geometry.attributes.color.array[3 * pointIndex + 2] = 0.0;
        positions_temp.push(
          this.points.geometry.attributes.position.array[3 * pointIndex],
          this.points.geometry.attributes.position.array[3 * pointIndex + 1],
          this.points.geometry.attributes.position.array[3 * pointIndex + 2]
        )
        switch (pointType) {
          case 0:
            colors_temp.push(0, 1, 1)
            break
          case 1:
            colors_temp.push(1 / 255, 1 / 255, 1)
            break
          case 2:
            colors_temp.push(218 / 255, 165 / 255, 32 / 255)
            break
          case 3:
            colors_temp.push(1, 1, 0)
            break
          case 4:
            colors_temp.push(1, 155 / 255, 0)
            break
          case 5:
            colors_temp.push(138 / 255, 43 / 255, 226 / 255)
            break
          case 6:
            colors_temp.push(220 / 255, 20 / 255, 60 / 255)
            break
          case 7:
            colors_temp.push(0, 1, 0)
            break
          case 8:
            colors_temp.push(1 / 255, 1 / 255, 1 / 255)
            break
          case 9:
            colors_temp.push(1, 1, 1)
            break
          case 10:
            colors_temp.push(1, 1, 1)
            break
          case 11:
            colors_temp.push(1, 1, 1)
            break
          case 12:
            colors_temp.push(1, 1, 1)
            break
          case 13:
            colors_temp.push(1, 1, 1)
            break
          case 14:
            colors_temp.push(1, 1, 1)
            break
          default:
            colors_temp.push(1, 1, 1)
            break
        }
        // if(this.points.geometry.attributes.customColumn.array[2*i +1] == 1)
        //   colors_temp.push(1, 1, 1);
        // else if(this.points.geometry.attributes.customColumn.array[2*i +1] == 2)
        //   colors_temp.push(1, 1, 255);
        // else if(this.points.geometry.attributes.customColumn.array[2*i +1] == 3)
        //   colors_temp.push(255, 0, 0);
        // else if(this.points.geometry.attributes.customColumn.array[2*i +1] == 4)
        //   colors_temp.push(0, 255, 0);
        // else
        // colors_temp.push(0, 0, 255);
        // }
      }
      geometry_temp.setAttribute('position', new THREE.Float32BufferAttribute(positions_temp, 3))
      geometry_temp.setAttribute('color', new THREE.Float32BufferAttribute(colors_temp, 3))
      geometry_temp.computeBoundingSphere()
      let canvas_temp = document.createElement('canvas')
      canvas_temp.width = 100
      canvas_temp.height = 100
      let context = canvas_temp.getContext('2d')
      context.fillStyle = '#FF9933'
      context.arc(50, 50, 45, 0, 2 * Math.PI)
      context.fill()
      let texture = new THREE.Texture(canvas_temp)
      texture.needsUpdate = true
      let material_temp = new THREE.PointsMaterial({ size: 2 })
      material_temp.sizeAttenuation = false
      material_temp.color.setHex(0xffffff)
      material_temp.sizeAttenuation = false
      material_temp.vertexColors = true
      material_temp.depthTest = false
      material_temp.fog = false
      let points_temp = new THREE.Points(geometry_temp, material_temp)
      this.scene.add(points_temp)
      this.keyPoints.push(points_temp)
      this.controls.update()
    },
    calCos(a, b) {
      // 点积
      let dotProduct = a[0] * b[0] + a[1] * b[1]
      let d = Math.sqrt(a[0] * a[0] + a[1] * a[1]) * Math.sqrt(b[0] * b[0] + b[1] * b[1])
      return dotProduct / d
    },
    keypointsRender(x, y, z, vertices_2d) {
      function GetCross(p1, p2, p) {
        return (p2.x - p1.x) * (p.y - p1.y) - (p.x - p1.x) * (p2.y - p1.y)
      }
      function IsPointInMatrix(p1, p2, p3, p4, p) {
        let isPointIn = GetCross(p1, p2, p) * GetCross(p3, p4, p) >= 0 && GetCross(p2, p3, p) * GetCross(p4, p1, p) >= 0
        return isPointIn
      }
      if (this.highLightCubePoints !== 'false') {
        let geometry_temp = new THREE.BufferGeometry()
        let positions_temp = []
        let colors_temp = []
        let max_x = Math.max(x[0], x[1], x[2], x[3])
        let max_y = Math.max(y[0], y[1], y[2], y[3])
        let min_x = Math.min(x[0], x[1], x[2], x[3])
        let min_y = Math.min(y[0], y[1], y[2], y[3])
        let min_z = Math.min(z[0], z[4])
        let max_z = Math.max(z[0], z[4])
        for (let i = 0; i < this.points.geometry.attributes.position.array.length / 3; i++) {
          if (
            this.points.geometry.attributes.position.array[3 * i] > max_x ||
            this.points.geometry.attributes.position.array[3 * i] < min_x
          )
            continue
          if (
            this.points.geometry.attributes.position.array[3 * i + 1] > max_y ||
            this.points.geometry.attributes.position.array[3 * i + 1] < min_y
          )
            continue
          if (
            this.points.geometry.attributes.position.array[3 * i + 2] > max_z ||
            this.points.geometry.attributes.position.array[3 * i + 2] < min_z
          )
            continue
          let pointA = new THREE.Vector3(
            parseFloat(this.points.geometry.attributes.position.array[3 * i]),
            parseFloat(this.points.geometry.attributes.position.array[3 * i + 1]),
            parseFloat(this.points.geometry.attributes.position.array[3 * i + 2])
          )
          let pointA_2d = new THREE.Vector2(
            this.points.geometry.attributes.position.array[3 * i],
            this.points.geometry.attributes.position.array[3 * i + 1]
          )
          if (IsPointInMatrix(vertices_2d[0], vertices_2d[1], vertices_2d[2], vertices_2d[3], pointA_2d)) {
            // https://www.wjceo.com/blog/threejs2/2020-09-01/202.html
            // let _localPosition = pointA.applyMatrix4(new THREE.Matrix4().getInverse(bb.matrixWorld));
            // if(bb.containsPoint(pointA)) {
            if (this.points.geometry.attributes.color) {
              this.points.geometry.attributes.color.array[3 * i] = 1.0
              this.points.geometry.attributes.color.array[3 * i + 1] = 0.0
              this.points.geometry.attributes.color.array[3 * i + 2] = 0.0
            }
            positions_temp.push(
              parseFloat(this.points.geometry.attributes.position.array[3 * i]),
              parseFloat(this.points.geometry.attributes.position.array[3 * i + 1]),
              parseFloat(this.points.geometry.attributes.position.array[3 * i + 2])
            )
            colors_temp.push(1, 1, 1)
          }
        }
        geometry_temp.setAttribute('position', new THREE.Float32BufferAttribute(positions_temp, 3))
        geometry_temp.setAttribute('color', new THREE.Float32BufferAttribute(colors_temp, 3))
        geometry_temp.computeBoundingSphere()
        let canvas_temp = document.createElement('canvas')
        canvas_temp.width = 100
        canvas_temp.height = 100
        let context = canvas_temp.getContext('2d')
        context.fillStyle = 'rgb(255,255,255)'
        context.arc(50, 50, 45, 0, 2 * Math.PI)
        context.fill()
        let texture = new THREE.Texture(canvas_temp)
        texture.needsUpdate = true
        let material_temp = new THREE.PointsMaterial({
          size: 6,
          vertexColors: THREE.VertexColors,
          depthTest: false,
          fog: false,
          map: texture,
        })
        material_temp.sizeAttenuation = false
        let points_temp = new THREE.Points(geometry_temp, material_temp)
        this.scene.add(points_temp)
        this.keyPoints.push(points_temp)
        return [geometry_temp, material_temp]
      }
      return null
    },
    makeTextSprite(message, parameters) {
      if (parameters === undefined) parameters = {}
      var fontface = parameters.hasOwnProperty('fontface') ? parameters['fontface'] : 'Arial'
      var fontsize = parameters.hasOwnProperty('fontsize') ? parameters['fontsize'] : this.pointTextFontSize
      var borderThickness = parameters.hasOwnProperty('borderThickness') ? parameters['borderThickness'] : 1
      var borderColor = parameters.hasOwnProperty('borderColor')
        ? parameters['borderColor']
        : { r: 0, g: 0, b: 0, a: 1.0 }
      var backgroundColor = parameters.hasOwnProperty('backgroundColor')
        ? parameters['backgroundColor']
        : { r: 255, g: 255, b: 255, a: 0.95 }
      var canvas = document.createElement('canvas')
      var context = canvas.getContext('2d')
      context.font = 'Bold ' + fontsize + 'px ' + fontface
      var metrics = context.measureText(message)
      var textWidth = metrics.width
      context.fillStyle =
        'rgba(' + backgroundColor.r + ',' + backgroundColor.g + ',' + backgroundColor.b + ',' + backgroundColor.a + ')'
      context.strokeStyle =
        'rgba(' + borderColor.r + ',' + borderColor.g + ',' + borderColor.b + ',' + borderColor.a + ')'
      context.lineWidth = borderThickness
      this.roundRect(
        context,
        borderThickness / 2,
        borderThickness / 2,
        textWidth + borderThickness,
        fontsize * 1.4 + borderThickness,
        textWidth / 2
      )
      context.fillStyle = 'white'
      context.fillText(message, borderThickness, fontsize + borderThickness)
      var texture = new THREE.Texture(canvas)
      texture.needsUpdate = true
      var spriteMaterial = new THREE.SpriteMaterial({
        map: texture,
        depthWrite: false,
        transparent: true,
        clipShadows: true,
        depthTest: false,
      })
      // spriteMaterial.sizeAttenuation = false;
      var spritey = new THREE.Sprite(spriteMaterial)
      spritey.scale.set(4, 2, 1.0)
      return spritey
    },
    roundRect(ctx, x, y, w, h, r) {
      ctx.beginPath()
      ctx.moveTo(x + r, y)
      ctx.lineTo(x + w - r, y)
      ctx.quadraticCurveTo(x + w, y, x + w, y + r)
      ctx.lineTo(x + w, y + h - r)
      ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h)
      ctx.lineTo(x + r, y + h)
      ctx.quadraticCurveTo(x, y + h, x, y + h - r)
      ctx.lineTo(x, y + r)
      ctx.quadraticCurveTo(x, y, x + r, y)
      ctx.closePath()
      ctx.fill()
      ctx.stroke()
    },
    showSelectedPoint(x, y, z) {
      let canvas_temp0 = document.createElement('canvas')
      canvas_temp0.width = 100
      canvas_temp0.height = 100
      let context0 = canvas_temp0.getContext('2d')
      context0.fillStyle = '#ffffff'
      context0.arc(50, 50, 45, 0, 2 * Math.PI)
      context0.fill()
      let texture0 = new THREE.Texture(canvas_temp0)
      texture0.needsUpdate = true
      let geometry = new THREE.Geometry() //声明一个空几何体对象
      let p1 = new THREE.Vector3(x, y, z)
      geometry.vertices.push(p1)
      let material = new THREE.PointsMaterial({
        color: 0xffffff,
        size: 10, //点对象像素尺寸
        depthTest: false,
        map: texture0,
      })
      material.sizeAttenuation = false
      material.fog = false
      this.selectPointObject = new THREE.Points(geometry, material)
      this.scene.add(this.selectPointObject)
    },
    onWindowResize() {
      if (this.camera) {
        // this.loadDrawing(this.fileList[this.currentIndex].mQaResultId);
        this.camera.aspect = this.container.offsetWidth / this.container.offsetHeight
        this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
        this.camera.updateProjectionMatrix()
        this.renderer.render(this.scene, this.camera)
      }
    },
    onMouseDown(event) {
      this.mouseDown = true
      event.preventDefault()
      this.selectedObject = {
        a1: '',
        remark: '',
        attributes: [],
        type: '3d',
        imageIndex: '',
        errorType: '',
        mPoint: {
          x: -1,
          y: -1,
          z: -1,
        },
        elementInstance: null,
      }
      this.scene.remove(this.selectPointObject)
      let rect = this.renderer.domElement.getBoundingClientRect()
      this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
      this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1
      this.raycaster.setFromCamera(this.mouse, this.camera)
      let intersects = this.raycaster.intersectObjects(this.cubeInstances, true)
      if (intersects.length > 0) {
        if (intersects[0].object.type == 'Mesh') {
          if (this.INTERSECTED) {
            let _array = intersects[0].object.tag.split(';')
            this.selectedObject.a1 = _array[1]
            this.selectedObject.remark = this.elementsRemark['ball-' + _array[1] + '-3d']
              ? this.elementsRemark['ball-' + _array[1] + '-3d'].remark
              : ''
            this.selectedObject.errorType = this.elementsRemark['ball-' + _array[1] + '-3d']
              ? this.elementsRemark['ball-' + _array[1] + '-3d'].errorType
              : ''
            this.selectedObject.mPoint = intersects[0].object.mPoint
            this.selectedObject.elementInstance = intersects[0].object.remarkLabel
            this.selectedObject.attributes = []
            for (let i = 1; i <= 9; i++) {
              if (_array[i] && _array[i] != null && _array[i] != '' && _array[i] != 'null') {
                try {
                  let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_3d'))
                  let _values = jsonObject.values[_array[i]]
                  if (_values == null || _values == undefined || _values == '') _values = _array[i]
                  let key = jsonObject.typeDesc
                  let value = _values
                  let _data = {
                    key,
                    value,
                  }
                  this.selectedObject.attributes.push(_data)
                } catch {}
              }
            }
            this.highlight_objects('3d')
          }
        }
      } else if (event.ctrlKey) {
        let intersectPoints = this.raycaster.intersectObjects(this.scene.children, true)
        let intersection = intersectPoints.length > 0 ? intersectPoints[0] : null
        if (intersection !== null && intersection.object.type === 'Points') {
          let suggestionMsg = prompt('描述')
          if (suggestionMsg === null) {
            alert(suggestionMsg)
            return
          }
          let params = {
            backgroundColor: { r: 255, g: 0, b: 0, a: 1 },
            fontsize: 48,
          }
          let remarkLabel = this.makeTextSprite(' 验 ', params)
          remarkLabel.position.set(intersection.point.x, intersection.point.y, intersection.point.z)
          this.scene.add(remarkLabel)
          this.remarkLabelList.push(remarkLabel)
          let missId = 'lou-3d-' + remarkLabel.id
          remarkLabel.missId = missId
          this.selectedObject.a1 = missId
          this.selectedObject.errorType = 'miss_mark'
          this.selectedObject.elementInstance = remarkLabel
          this.selectedObject.mPoint = {
            x: intersection.point.x,
            y: intersection.point.y,
            z: intersection.point.z,
          }
          this.showSelectedPoint(intersection.point.x, intersection.point.y, intersection.point.z)
          this.handleElementComments(missId, suggestionMsg)
        } else if (intersection !== null && intersection.object.type === 'Sprite' && intersection.object.missId) {
          this.selectedObject.elementInstance = intersection.object
          this.handleElementComments(intersection.object.missId, '')
          this.scene.remove(intersection.object)
          for (let i = 0; i < this.remarkLabelList.length; i++) {
            if (this.remarkLabelList[i].missId && this.remarkLabelList[i].missId == intersection.object.missId) {
              this.remarkLabelList.splice(i, 1)
              break
            }
          }
        }
      } else {
        if (event.buttons != 1) {
          return
        }
        let intersectPoints = this.raycaster.intersectObjects(this.scene.children, true)
        let intersection = intersectPoints.length > 0 ? intersectPoints[0] : null
        if (intersection !== null && intersection.object.type === 'Sprite' && intersection.object.missId) {
          this.showSelectedPoint(
            intersection.object.position.x,
            intersection.object.position.y,
            intersection.object.position.z
          )
        }
      }
    },
    onMouseUp(event) {
      this.mouseDown = false
    },
    onMouseMove(event) {
      if (this.renderer.domElement) {
        event.preventDefault()
        let rect = this.renderer.domElement.getBoundingClientRect()
        this.mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
        this.mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1

        this.raycaster.setFromCamera(this.mouse, this.camera)
        let intersects = this.raycaster.intersectObjects(this.cubeInstances, true)
        if (intersects.length > 0) {
          if (intersects[0].object != this.INTERSECTED) {
            if (intersects[0].object.type == 'Mesh') {
              this.renderEnabled = true
              // restore previous intersection object (if it exists) to its original color
              if (this.INTERSECTED) this.INTERSECTED.material.color.setHex(this.INTERSECTED.currentHex)
              // store reference to closest object as current intersection object
              this.INTERSECTED = intersects[0].object
              // store color of closest object (for later restoration)
              this.INTERSECTED.currentHex = this.INTERSECTED.material.color.getHex()
              // set a new color for closest object
              this.INTERSECTED.material.color.setHex(0xffff00)

              var message = intersects[0].object.tag
              let worldVector = new THREE.Vector3(
                intersects[0].object.geometry.boundingSphere.center.x,
                intersects[0].object.geometry.boundingSphere.center.y,
                intersects[0].object.geometry.boundingSphere.center.z
              )
              //世界坐标转标准设备坐标
              let stdVector = worldVector.project(this.camera)
              let a = window.innerWidth / 2
              let b = window.innerHeight / 2
              //标准设备坐标转屏幕坐标x,y
              let x = Math.round(stdVector.x * a + a)
              let y = Math.round(-stdVector.y * b + b)
              this.ShowTip(message, x, y)
              // }
            } else {
              this.HideTip()
            }
          }
        } else {
          this.HideTip()
          if (this.INTERSECTED) {
            this.INTERSECTED.material.color.setHex(this.INTERSECTED.currentHex)
            this.INTERSECTED = null
          }
        }

        this.renderer.render(this.scene, this.camera)
      }
    },
    onMouseWheel(event) {
      this.renderEnabled = true
    },
    animate() {
      if (this.renderer) {
        this.animationFrameId = requestAnimationFrame(this.animate.bind(this))
        if ((this.renderEnabled || this.mouseDown) && !this.loading) {
          this.renderEnabled = this.mouseDown
          this.controls.update()
          this.renderer.render(this.scene, this.camera)
        }
      }
    },
    loadJsonPCD(pointsCloud) {
      pointsCloud = JSON.parse(pointsCloud)
      let customColumn = []
      let positions = []
      let color = []
      for (var i = 0; i < pointsCloud.length; i++) {
        let x = parseFloat(pointsCloud[i][0])
        let y = parseFloat(pointsCloud[i][1])
        let z = parseFloat(pointsCloud[i][2])
        positions.push(x, y, z)
        let tmp
        if (pointsCloud[i].length == 6) {
          customColumn.push(parseFloat(pointsCloud[i][4]), parseFloat(pointsCloud[i][5]))
          tmp = colorRender(parseFloat(pointsCloud[i][3]), 'split')
        } else {
          tmp = colorRender(z, this.renderType)
        }
        color.push(tmp[0], tmp[1], tmp[2])
      }
      let canvas_temp0 = document.createElement('canvas')
      canvas_temp0.width = 100
      canvas_temp0.height = 100
      let context0 = canvas_temp0.getContext('2d')
      context0.fillStyle = '#ffffff'
      context0.arc(50, 50, 45, 0, 2 * Math.PI)
      context0.fill()
      let texture0 = new THREE.Texture(canvas_temp0)
      texture0.needsUpdate = true
      let material = new THREE.PointsMaterial({
        size: 2,
        vertexColors: THREE.VertexColors,
        depthTest: false,
        map: texture0,
      })
      material.color.setHex(0xffffff)
      material.sizeAttenuation = false
      material.vertexColors = THREE.VertexColors
      material.depthTest = false
      material.fog = false
      let geometry = new THREE.BufferGeometry()
      geometry.attributes.color = new THREE.Float32BufferAttribute(color, 3)
      geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3))
      geometry.setAttribute('customColumn', new THREE.Float32BufferAttribute(customColumn, 2))
      geometry.computeBoundingSphere()
      return new THREE.Points(geometry, material)
    },
    async getPointsCloud() {
      // this.loading = true;
      this.startLoading = true
      this.loadingTimer()
      this.renderEnabled = true
      let mQaResultId = this.fileList[this.currentIndex].mQaResultId
      // this.remark = "";
      this.selectedObject = {
        a1: '',
        remark: '',
        attributes: [],
        type: '',
        imageIndex: '',
      }
      this.elementsRemark = {}
      this.currentStatus = this.fileList[this.currentIndex].mQaResult
        ? this.fileList[this.currentIndex].mQaResult
        : '待验收'

      await listRemarkBall({ taskId: this.queryParams.taskId, mQaResultId: mQaResultId }).then((response) => {
        let remarkBallList = response.rows
        if (remarkBallList) {
          remarkBallList.forEach((ball) => {
            let key = ball.trackId
            if (!key.startsWith('lou-')) {
              key += '-' + ball.mType
            }
            this.elementsRemark[key] = ball.remark
            this.elementsRemark['ball-' + key] = ball
          })
        }
      })
      this.$getItem('MA:' + mQaResultId + '', (err, readValue) => {
        if (readValue) {
          if (readValue.blob) {
            let blobUrl = URL.createObjectURL(readValue.blob)
            let loader = new PCDLoader()
            loader.renderType = this.renderType
            loader.load(blobUrl, (points) => {
              this.pointsCloudData = points
              this.annotation = readValue.annotation
              this.threejsRender()
            })
          } else if (readValue.pointsCloud) {
            this.pointsCloudData = this.loadJsonPCD(readValue.pointsCloud)
            this.annotation = readValue.annotation
            this.threejsRender()
          }
        } else {
          pointsCloudDetails(mQaResultId).then((res) => {
            if (res.fileType === 'pcd') {
              pcdBlob(mQaResultId).then((response) => {
                let blob = new Blob([response.data], { type: 'application/octet-stream' })
                let blobUrl = URL.createObjectURL(blob)
                let loader = new PCDLoader()
                loader.renderType = this.renderType
                loader.load(blobUrl, (points) => {
                  this.pointsCloudData = points
                  this.annotation = res.annotation
                  this.threejsRender()
                  let annotation = res.annotation
                  let _data = {
                    pointsCloud: this.pointsCloudData,
                    annotation,
                  }
                  this.saveToCacheDB('MA:' + mQaResultId + '', _data)
                })
              })
            } else if (res.fileType === 'jbin') {
              this.pointsCloudData = this.loadJsonPCD(res.pointsCloud)
              this.annotation = res.annotation
              this.threejsRender()
              let pointsCloud = res.pointsCloud
              let annotation = res.annotation
              let _data = {
                pointsCloud,
                annotation,
              }
              this.saveToCacheDB('MA:' + mQaResultId + '', _data)
            }
          })
        }
        let cachePromise = new Promise((resolve, reject) => {
          this.cachePreAndNext()
          resolve('cache finished.')
        })
        cachePromise.then(
          (message) => {
            console.log(message)
          },
          (message) => {
            console.log(message)
          }
        )
      })
    },
    loadingTimer() {
      let promise1 = new Promise((resolve, reject) => {
        let _this = this
        setTimeout(function () {
          if (_this.startLoading) {
            _this.loading = true
          }
        }, 1000)
        resolve('loading timer.')
      })
      return promise1
    },
    threejsRender() {
      this.addPoints()
      this.addSplitPoints()
      this.loading = false
      this.startLoading = false
      this.animate()
      this.setPosition(this.selectedObjectA1, null, '', null, null, null)
    },
    saveToCacheDB(_key, _value) {
      this.$setItem(_key, _value, function () {})
    },
    cachePreAndNext() {
      for (let i = 1; this.currentIndex - i >= 0 && i <= 3; i++) {
        this.cacheFile(this.fileList[this.currentIndex - i].mQaResultId)
      }
      for (let i = 1; this.currentIndex + i < this.fileList.length && i <= 3; i++) {
        this.cacheFile(this.fileList[this.currentIndex + i].mQaResultId)
      }
    },
    cacheFile(qaResultId) {
      this.$getItem('MA:' + qaResultId + '', (err, readValue) => {
        if (!readValue) {
          pointsCloudDetails(qaResultId).then((res) => {
            if (res.fileType === 'pcd') {
              pcdBlob(qaResultId).then((response) => {
                let blob = new Blob([response.data], { type: 'application/octet-stream' })
                let annotation = res.annotation
                let _data = {
                  blob,
                  annotation,
                }
                this.saveToCacheDB('MA:' + qaResultId + '', _data)
              })
            } else if (res.fileType === 'jbin') {
              let pointsCloud = res.pointsCloud
              let annotation = res.annotation
              let _data = {
                pointsCloud,
                annotation,
              }
              this.saveToCacheDB('MA:' + qaResultId + '', _data)
            }
          })
          if (this.imgCount === 1) {
            imageFile(qaResultId, 0).then((response) => {
              let imageSrc = response.imageSrc
              let annotation = response.annotation
              let _data = {
                imageSrc,
                annotation,
              }
              // this.$setItem("MA:" + qaResultId + ":img", _data, ()=> {});
            })
          } else {
            for (let j = 0; j < this.imgCount; j++) {
              imageFile(qaResultId, j + 1).then((response) => {
                let imageSrc = response.imageSrc
                let annotation = response.annotation
                let _data = {
                  imageSrc,
                  annotation,
                }
                // this.$setItem("MA:" + qaResultId + ":img:" + (j+1), _data, ()=> {});
              })
            }
          }
        }
      })
    },
    handleElementComments(id, remark) {
      let markRemarkId
      let remarkBall = {
        // remarkId: undefined,
        taskId: this.fileList[this.currentIndex].taskId,
        mQaResultId: this.fileList[this.currentIndex].mQaResultId,
        fileName: this.fileList[this.currentIndex].fileId,
        trackId: id, //this.selectedObject.a1,
        mType:
          this.selectedObject.type + (this.selectedObject.type == '2d' ? '-' + this.selectedObject.imageIndex : ''),
        errorType: this.selectedObject.errorType,
        remark: remark,
        x: this.selectedObject.mPoint.x,
        y: this.selectedObject.mPoint.y,
        z: this.selectedObject.mPoint.z,
      }
      if ((remark && remark !== '') || (this.selectedObject.errorType && this.selectedObject.errorType != '')) {
        if (!remark || remark === '') {
          for (let i = 0; i < this.errorTypeOptions.length; i++) {
            let errorTypeDict = this.errorTypeOptions[i]
            if (errorTypeDict.dictValue === this.selectedObject.errorType) remarkBall.remark = errorTypeDict.dictLabel
            this.selectedObject.remark = remarkBall.remark
          }
        }
        addRemarkBall(remarkBall).then((response) => {
          if (response.code === 200) {
            if (this.selectedObject.elementInstance)
              this.selectedObject.elementInstance.markRemarkId = response.markRemarkId
            this.msgSuccess('更新成功')
          } else {
            this.msgError(response.msg)
          }
        })
      } else {
        delRemarkBall(this.selectedObject.elementInstance.markRemarkId).then((response) => {
          if (response.code === 200) {
            this.msgSuccess('删除成功')
          } else {
            this.msgError(response.msg)
          }
        })
      }
      this.detailsDialogOpen = false
      if (id == null || id == '' || id == undefined) return
      if (!id.startsWith('lou-')) {
        id =
          id +
          '-' +
          this.selectedObject.type +
          (this.selectedObject.imageIndex != '' ? '-' + this.selectedObject.imageIndex : '')
      }
      this.elementsRemark[id] = this.selectedObject.remark
      this.elementsRemark['ball-' + this.selectedObject.a1 + '-' + remarkBall.mType] = this.selectedObject.errorType
      // this.handleComments("");
      if (!id.startsWith('lou-')) {
        this.highlight_objects('')
      }
    },
    handleComments(ret) {
      this.fileList[this.currentIndex].mQaResult = ret
      // let _remark = (this.remark == null || this.remark == "")? "详情": this.remark;
      // for(let prop in this.elementsRemark){
      //   if(this.elementsRemark[prop] && this.elementsRemark[prop] !== "") {
      //     _remark += ";"
      //     _remark += prop + ":" + this.elementsRemark[prop];
      //   }
      // }
      // _remark = _remark === "详情" ? "": _remark;
      // this.fileList[this.currentIndex].remark = _remark;
      let data = {
        taskId: this.fileList[this.currentIndex].taskId,
        fileId: this.fileList[this.currentIndex].fileId,
        markResultId: this.fileList[this.currentIndex].markResultId,
        markType: this.fileList[this.currentIndex].markType,
        mQaResultId: this.fileList[this.currentIndex].mQaResultId,
        mQaResult: this.fileList[this.currentIndex].mQaResult,
        createBy: this.fileList[this.currentIndex].createBy,
        createTime: this.fileList[this.currentIndex].createTime,
        updateBy: this.fileList[this.currentIndex].updateBy,
        updateTime: this.fileList[this.currentIndex].updateTime,
        remark: this.fileList[this.currentIndex].remark,
      }
      updateResult(data).then((response) => {
        if (response.code === 200) {
          if (ret == '') {
            this.msgSuccess('批注更新成功。')
          } else if (this.currentIndex < this.fileList.length - 1) {
            this.changePage(1)
            this.msgSuccess('标注结果' + ret + '，开始载入下一张。')
          } else {
            this.msgSuccess('标注结果' + ret + '，已到达最后一张。')
          }
        } else {
          this.msgError(response.msg)
        }
      })
    },
    changePage(num) {
      cancelAnimationFrame(this.animationFrameId)
      // this.$lengthOfStorage().then((count)=>{
      if (this.currentIndex + num < 0 || this.currentIndex + num >= this.fileList.length) return
      this.currentIndex += num
      let query = {
        taskId: this.queryParams.taskId,
        mQaResultId: this.fileList[this.currentIndex].mQaResultId,
      }
      this.$router.replace({
        path: '/mark/pointCloudSplit',
        query: query,
      })

      this.getPointsCloud()
      this.$store.dispatch('mqaResultCurrentIndexCached', this.currentIndex)
      if (count >= 25) {
        this.removeAnnotationCache('MA:')
      }
      // });
    },
    threejsFullScreen() {
      this.isFullscreen = !this.isFullscreen
      if (this.isFullscreen) {
        try {
          screenfull.request(document.getElementById('qaOnline'))
        } catch (err) {}
      } else {
        try {
          screenfull.toggle()
        } catch (err) {}
      }
    },
    returnFileList(e) {
      // history.back();
      history.pushState(null, null, document.URL)
      if (e) e.preventDefault()
      this.$router.replace({ path: '/mark/result', query: { taskId: this.queryParams.taskId } })
      for (let i = 0; i < this.$store.state.tagsView.visitedViews.length; i++) {
        if (this.$store.state.tagsView.visitedViews[i].name === 'pointCloudSplit') {
          this.$store.dispatch('tagsView/delView', this.$store.state.tagsView.visitedViews[i])
        }
      }
    },
    keyDownHandler(e) {
      if (
        $(document.activeElement).hasClass('skip-shortcuts') ||
        $(document.activeElement).parent().hasClass('skip-shortcuts')
      ) {
        return
      }
      // enter
      if (document.activeElement.id == 'remarkInput') {
        if (e.keyCode == 13 || e.keyCode == 32) {
          e.preventDefault()
        }
        return
      }
      if (document.activeElement.id == 'detailRemarkInput') {
        if (e.keyCode == 13 || e.keyCode == 32) {
          e.preventDefault()
          if (e.keyCode == 13 && this.selectedObject && this.selectedObject.remark) {
            this.handleElementComments(this.selectedObject.a1, this.selectedObject.remark)
          }
        }
        return
      }
      if (document.activeElement.id == 'trackID') {
        if (e.keyCode == 13 && this.selectedObject && this.selectedObject.a1) {
          this.highlight_objects('')
        }
      }
      if (e.keyCode == 13) {
        e.preventDefault()
        return
      }
      // space
      if (e.keyCode == 32) {
        this.showAttributesText = !this.showAttributesText
        this.ShowAttributesText(this.showAttributesText)
        e.preventDefault()
        return
      }
      // e
      if (e.keyCode == 69) {
        e.preventDefault()
        if (this.selectedObject.a1 !== '') {
          this.HideTip()
          this.detailsDialogOpen = true
          let detailRemarkInput = document.getElementById('detailRemarkInput')
          if (detailRemarkInput) detailRemarkInput.focus()
        }
      }
      // t
      else if (e.keyCode == 84) {
        e.preventDefault()
        let remarkInput = document.getElementById('remarkInput')
        remarkInput.focus()
      }
      // q
      else if (e.keyCode == 81) {
        history.back()
      }
      // f
      else if (e.keyCode == 70) {
        if (!this.isFullscreen) {
          this.threejsFullScreen()
        }
      }
      // a
      else if (e.keyCode == 65) {
        if (this.currentIndex >= 1 && this.loading !== true) {
          this.changePage(-1)
        }
      }
      // d
      else if (e.keyCode == 68) {
        if (this.currentIndex < this.fileList.length - 1 && this.loading !== true) {
          this.changePage(1)
        }
      }
      // s
      else if (e.keyCode == 83 && this.loading !== true) {
        this.handleComments('通过')
      }
      // w
      else if (e.keyCode == 87 && this.loading !== true) {
        this.handleComments('驳回')
      }
      // r
      else if (e.keyCode == 82 && this.loading !== true) {
        this.handleComments('挂起')
      }
    },
    showColorDialog() {
      this.showColorDialogVar = !this.showColorDialogVar
      this.jumpToBottom()
      if (this.showColorDialogVar) {
        this.camera.aspect = this.container.offsetWidth / (this.container.offsetHeight + 130)
        this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight + 130)
        this.camera.updateProjectionMatrix()
      } else {
        this.camera.aspect = this.container.offsetWidth / this.container.offsetHeight
        this.renderer.setSize(this.container.offsetWidth, this.container.offsetHeight)
        this.camera.updateProjectionMatrix()
      }
    },
    jumpToBottom() {
      // const aLink = document.createElement('aaa');
      // aLink.href = "#bottomDiv";
      // document.body.appendChild(aLink);
      // aLink.click();
      // document.body.appendChild(aLink);
      // document.body.scrollTo(0, document.body.scrollHeight);
      document.querySelector('#bottomDiv').scrollIntoView(true)
    },
    qaTaskQuery() {
      // getQaTask(this.queryParams.taskId).then(response => {
      //   this.taskPath = response.data.taskName;
      //   if(response.data.parentId !== "0") {
      //     getQaTask(response.data.parentId).then(response => {
      //       this.taskPath = response.data.taskName + " -> " + this.taskPath;
      //       if(response.data.parentId !== "0") {
      //         getQaTask(response.data.parentId).then(response => {
      //           this.taskPath = response.data.taskName + " -> " + this.taskPath;
      //         });
      //       }
      //     });
      //   }
      // });
      let mQaResultId = this.$route.query.mQaResultId
      this.$getItem('QaTask:' + this.queryParams.taskId, (err, readValue) => {
        if (readValue) {
          this.$getItem(readValue.data.markAttributes, (err, attributes) => {
            if (attributes) {
              this.attributeNames = attributes
              this.renderType = this.selectDictLabel(this.attributeNames, 'renderType')
              this.cameraPosition = this.selectDictLabel(this.attributeNames, 'cameraPosition')
              this.highLightCubePoints = this.selectDictLabel(this.attributeNames, 'highLightCubePoints')
            } else {
              this.getDicts(readValue.data.markAttributes).then((res1) => {
                this.attributeNames = res1.data
                this.renderType = this.selectDictLabel(this.attributeNames, 'renderType')
                this.cameraPosition = this.selectDictLabel(this.attributeNames, 'cameraPosition')
                this.highLightCubePoints = this.selectDictLabel(this.attributeNames, 'highLightCubePoints')
              })
            }
          })
          this.$getItem(readValue.data.markAttributes + '_colors', (err, attributesColors) => {
            if (attributesColors) {
              this.colorNames = attributesColors
            } else {
              this.getDicts(readValue.data.markAttributes + '_colors').then((res1) => {
                this.colorNames = res1.data
              })
            }
          })
        } else {
          getQaTask(this.queryParams.taskId).then((response) => {
            this.getDicts(response.data.markAttributes).then((res1) => {
              this.attributeNames = res1.data
              this.renderType = this.selectDictLabel(this.attributeNames, 'renderType')
              this.cameraPosition = this.selectDictLabel(this.attributeNames, 'cameraPosition')
              this.highLightCubePoints = this.selectDictLabel(this.attributeNames, 'highLightCubePoints')
            })
            this.getDicts(response.data.markAttributes + '_colors').then((res1) => {
              this.colorNames = res1.data
            })
          })
        }
      })
    },
    contextmenuHandler(e) {
      e.preventDefault()
    },
    intervalFunc() {
      if (this.loading) {
        this.seconds++
      } else {
        this.seconds = 0
      }
    },
  },
  beforeRouteEnter(to, from, next) {
    next((vm) => {
      if (from.name === null) {
        // 捕获界面刷新事件，清除标注结果缓存
        vm.removeAnnotationCache('MA:')
      }
    })
  },
  created() {
    if (!this.$route.query.taskId || !this.$route.query.mQaResultId) this.$router.go(-1)
    this.queryParams.taskId = this.$route.query.taskId
    this.selectedObjectA1 = this.$route.query.selectedObjectA1
    window.addEventListener('contextmenu', this.contextmenuHandler, false)
    this.$store.dispatch('app/closeSideBar', { withoutAnimation: true })
    this.getDicts('mark_result_error_type').then((response) => {
      this.errorTypeOptions = response.data
    })
    // this.interval = setInterval(this.intervalFunc, 1000);
  },
  mounted() {
    this.qaTaskQuery()
    window.addEventListener('resize', this.onWindowResize, false)
    document.addEventListener('keydown', this.keyDownHandler, false)
    screenfull.on('change', (event) => {
      this.isFullscreen = screenfull.isFullscreen
    })
    listResult(this.queryParams).then((response) => {
      let mQaResultId = this.$route.query.mQaResultId
      this.fileList = response.rows
      for (var i = 0; i < response.total; i++) {
        if (mQaResultId == null || mQaResultId == this.fileList[i].mQaResultId) {
          this.currentIndex = i
          this.$store.dispatch('mqaResultCurrentIndexCached', this.currentIndex)
          this.init()
          // if(this.imgCount > 0) {
          // if(this.imgCount == 1)
          //   this.imgIndex = 0;
          // else
          //   this.imgIndex = 1;
          // this.loadDrawing(this.fileList[this.currentIndex].mQaResultId);
          // }
          this.getPointsCloud()
          break
        }
      }
      this.jumpToBottom()
    })
  },
  beforeDestroy() {
    clearInterval(this.interval)
    cancelAnimationFrame(this.animationFrameId)
    this.camera = null
    if (this.renderer) {
      this.renderer.domElement.removeEventListener('mousemove', this.onMouseMove, false)
      this.renderer.domElement.removeEventListener('mousedown', this.onMouseDown, false)
      this.renderer.forceContextLoss()
      this.renderer = null
    }
    window.removeEventListener('contextmenu', this.contextmenuHandler, false)
    window.removeEventListener('resize', this.onWindowResize, false)
    document.removeEventListener('keydown', this.keyDownHandler, false)
  },
}
</script>
<style lang="scss" scoped>
html,
body {
  width: 100%;
  height: 100%;
}

/* Scale canvas with resize attribute to full size */
canvas[resize] {
  width: 100%;
  height: auto;
}

.special_focus_toolTip {
  z-index: 7;
  position: absolute;
  display: none;
  width: 240px;
  height: 180px;
  border-style: solid;
  transition: left 0.4s cubic-bezier(0.23, 1, 0.32, 1), top 0.4s cubic-bezier(0.23, 1, 0.32, 1);
  background-color: rgba(50, 50, 50, 0.701961);
  border-width: 0px;
  border-color: #333333;
  border-radius: 4px;
  color: #ffffff;
  font-style: normal;
  font-variant: normal;
  font-weight: normal;
  font-stretch: normal;
  font-size: 14px;
  font-family: 'Microsoft YaHei';
  line-height: 21px;
  padding: 10px 10px;
  pointer-events: none;
}

.icon-list {
  height: calc(100vh - 155px);
  overflow-y: auto;
  .color-name {
    height: 30px;
    line-height: 30px;
    // margin-bottom: -5px;
    cursor: pointer;
    width: 50%;
    float: left;
    span {
      vertical-align: 0.3em;
      fill: currentColor;
      margin-left: 5px;
    }
  }
}
.img-canvas-list {
  height: 83vh;
  max-height: 83vh;
  background: #fff;
  border-bottom: 1px solid #e6ebf5;
  canvas {
    height: auto;
  }
}
.point-cloud-container {
  canvas {
    width: 100%;
    height: 100%;
  }
}
.plan-view-drawer {
  position: absolute;
  right: 0px;
  top: 0px;
  height: 83vh;
  z-index: 999;
  left: 80%;
  background: #fff;
}
.bottom-div {
  bottom: 0;
  height: 46px;
  line-height: 46px;
  padding: 0 10px;
  background: #fff;
  .el-form-item {
    margin: 0;
    display: inline-grid;
    vertical-align: middle;
  }
  .filename {
    word-wrap: break-word;
    word-break: break-all;
    display: flex;
    align-items: center;
    height: 46px;
    span {
      line-height: 18px;
    }
  }
  .color-name-btn {
    display: flex;
    align-items: center;
    height: 46px;
    margin-left: 15px;
  }
}
</style>
